#include <SGE.h>
#include "Bullet.h"
#include "Fighter.h"
#include "Enemy.h"

using namespace SGE;

Fighter fighter;

const int kMaxBullets = 100;
Bullet bullets[kMaxBullets];
int bulletIndex = 0; //traces the bullet currently being fired

const int kMaxEnemies = 100;
Enemy enemies[kMaxEnemies];
int enemyIndex = 0;

const int kMaxExplosion = 100;
SGE_Emitter explosions[kMaxExplosion];
int explosionIndex = 0;

//time to wait before spawning next enemy
float spawnDelay = 0.0f;

SGE_Sprite background;
SGE_Sound fireSound;
SGE_Sound explosionSound;


bool quit = false; //replaces hard coded false to quite game
//**REFACTORING TO SHORTEN UPDATE FUNCTION
void UpdateGameObjects(float deltaTime)
{

	//***FIGHTER UPDATE
	fighter.Update(deltaTime);

	//***BULLET UPDATE
	for(int i=0; i<kMaxBullets; i++)
	{
		bullets[i].Update(deltaTime);
	}

	//***ENEMY UPDATE
	for(int i=0; i<kMaxEnemies; i++)
	{
		enemies[i].Update(deltaTime);
	}

	//***Explosion UPDATE
	for(int i=0; i<kMaxExplosion ; i++)
	{
		explosions[i].Update(deltaTime);
	}
}

void FireBullets()
{
	//***INPUT
	//const int index2 = bulletIndex + 1;
	//const int index3 = bulletIndex + 2;

	if(Input_IsKeyPressed(Keys::SPACE))
	{
		const int index = bulletIndex;
		const int index1 = (bulletIndex+1)%kMaxBullets;
		const int index2 = (bulletIndex+2)%kMaxBullets;

		//check to see if bullet is not active and ready to be fired
		if (!bullets[index].isActive() &&
			!bullets[index1].isActive() &&
			!bullets[index2].isActive())
		{
			SVector2 pos = fighter.GetPosition();
			SVector2 vel(0.0f, -500.0f); //velocity shoots in the negative y direction because our coordinate system is top-down
			bullets[index].Fire(pos,vel); //fire bullet from fighter's position

			//modding maxBullets makes sure the remainder never goes beyond the limit
			//wraps index around to recycle bullets

			SVector2 pos2 = fighter.GetPosition();
			SVector2 vel2(-100.0f, -500.0f); 
			bullets[index1].Fire(pos2,vel2); 

			SVector2 pos3 = fighter.GetPosition();
			SVector2 vel3(100.0f, -500.0f); 
			bullets[index2].Fire(pos3,vel3); 

			bulletIndex = (index2 + 1) % kMaxBullets; 

			fireSound.Play();
		}

	}
}

//**************************EXCEEDING MAX BULLETS***************

void SpawnEnemies(float deltaTime)
{
	//spawn delay is decrementing by deltaTime this is called
	spawnDelay -= deltaTime;
	
	//when countdown (spawnDelay) reaches 0 
	if(spawnDelay <= 0)
	{
		//Time to spawn!
		if(!enemies[enemyIndex].isActive())
		{
			const int kWinWidth = IniFile_GetInt("WinWidth", 800);
			const float posX = kWinWidth *RandomFloat(0.1f, 0.9f);
			const float posY = -100.0f;

			SVector2 pos(posX, posY);

			enemies[enemyIndex].Spawn(pos);
			enemyIndex = (enemyIndex +1) % kMaxEnemies;
		}

		//Reset delay time by randomly generated float (between 0.5 and 2 seconds)
		spawnDelay = RandomFloat(0.5f, 2.0f);
	}
}
//****************************************


void CheckCollision()
{
	//loop through all enemies
	for(int e=0; e<kMaxEnemies; e++)
	{
		//if enemy is active
		if(enemies[e].isActive())
		{
			//check against every buller
			for(int b=0; b<kMaxBullets; b++)
			{
				if(bullets[b].isActive()) //here we have found 1 active enemy and 1 active bullet
				{
					SCircle eCircle = enemies[e].GetBoundingCircle();
					SCircle bCircle = bullets[b].GetBoundingCircle();

					float xDiff = eCircle.center.x - bCircle.center.x;
					float yDiff = eCircle.center.y - bCircle.center.y;
					
					//pythagorean to find connecting vector between bullet and enemy
					float distance = sqrt(xDiff * xDiff + yDiff * yDiff); 

					float radii = eCircle.radius + bCircle.radius;

					//if distance between e and b is less than combined radii, they have collided
					if(distance <= radii)
					{
						enemies[e].Kill();
						bullets[b].Kill();
						explosions[explosionIndex].SetPosition(eCircle.center);
						explosions[explosionIndex].Start(100.0f, true);
						explosionIndex = (explosionIndex + 1 ) % kMaxExplosion;
						explosionSound.Play();

						break; //breaks so we do not continues comparing
					}

				}
			}
		}
	}
}

void SGE_Initialize()
{
	background.Load("space.jpg");
	fireSound.Load("photongun1.wav");
	explosionSound.Load("explosion.wav");
	fighter.Load();

	//****SETTING INITIAL SPAWN POSITION TO CENTER OF SCREEN:
	// - obtain the dimensions of window from ini file
	// - construct vector 2 out of a percentage of window dimensions
	// - set position to constructed start position
	const int kWinWidth = IniFile_GetInt("WinWidth", 800);
	const int kWinHeight = IniFile_GetInt("WinHeight", 600);
	SVector2 startPosition(kWinWidth * 0.5f, kWinHeight * 0.75f);
	fighter.SetPosition(startPosition);

	//load array of bullets
	for(int i=0; i<kMaxBullets; i++)
	{
		bullets[i].Load();
	}

	//load pool of enemies
	for(int i=0; i<kMaxEnemies; i++)
	{
		enemies[i].Load();
	}

	//load explosion
	for(int i=0; i<kMaxExplosion ; i++)
	{
		explosions[i].Load("explosion.txt");
	}
	

}

void SGE_Terminate()
{
	background.Unload();
	fighter.Unload();

	for(int i=0; i<kMaxBullets; i++)
	{
		bullets[i].Unload();
	}

	for(int i=0; i<kMaxEnemies; i++)
	{
		enemies[i].Unload();
	}

	for(int i=0; i<kMaxExplosion ; i++)
	{
		explosions[i].Unload();
	}
	fireSound.Unload();
	explosionSound.Unload();
}

bool SGE_Update(float deltaTime)
{
	UpdateGameObjects(deltaTime);
	FireBullets();
	SpawnEnemies(deltaTime);
	CheckCollision();

	//virtual key codes: included in Input.h (accessed using Keys namespace)
	if(Input_IsKeyPressed(Keys::ESCAPE)) 
	{
		quit = true;
	}

	return quit;
}

void SGE_Render()
{
	background.Render();
	//***sge has a draw order, first statements called are bottom layer and so on
	for(int i=0; i<kMaxBullets; i++)
	{
		bullets[i].Render();
	}

	fighter.Render();	

	for(int i=0; i<kMaxEnemies; i++)
	{
		enemies[i].Render();
	}

	for(int i=0; i<kMaxExplosion ; i++)
	{
		explosions[i].Render(true);
	}
	

}